package wechat

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"net/http"
	"net/url"
	"regexp"
	"strings"
	"sync"
	"time"
	configswechat "wechat/src/configs/wechat"
	modelwechat "wechat/src/model/wechat"
	"wechat/src/service/ai"
	"wechat/src/tools"
)

type WechatUser struct {
	Host              string                         `json:"host"`
	HostPrefix        *modelwechat.Prefix            `json:"host_prefix"`
	Uuid              string                         `json:"uuid"`
	Cookie            []*http.Cookie                 `json:"cookie"`
	WebwxnewLoginPage *modelwechat.WebwxnewLoginPage `json:"webwxnew_login_page"`
	UserData          *modelwechat.UserData          `json:"user_data"`
	StartTime         int64                          `json:"start_time"`
	Cookies           map[string]string              `json:"cookies"`
	Ai                *ai.Robot                      `json:"ai"`
}

func User(wgp *sync.WaitGroup, statusTube chan string) {
	wechat := new(WechatUser)
	wechat.StartTime = time.Now().UnixMilli()
	//接收登录成功信号
	if err := wechat.successfulSignal(statusTube); err != nil {
		panic(err)
	}
	heartbeatTube := make(chan string, 1)

	//初始化登陆信息
	if err := wechat.webwxinit(); err != nil {
		panic(err)
	}

	//登录微信通知成功
	if err := wechat.webwxstatusnotify(); err != nil {
		panic(err)
	}

	//心跳
	wgp.Add(1)
	go wechat.synccheck(wgp, heartbeatTube)
	wgp.Add(1)
	go wechat.messaging(wgp, heartbeatTube)

	//处理接收到消息

	fmt.Println(wechat.Uuid)
}

func Restore(wgp *sync.WaitGroup) error {
	heartbeatTube := make(chan string, 1)
	//读取文件
	content, err := tools.FileRead(configswechat.CacheSaveFile)
	if err != nil {
		return errors.New(fmt.Sprintf("读取文件失败：%v", err))
	}
	var wechat *WechatUser
	if err := json.Unmarshal(content, &wechat); err != nil {
		return errors.New(fmt.Sprintf("格式转换失败：%v", err))
	}
	wechat.StartTime = time.Now().UnixMilli()
	wechat.CookieToJson()

	wgp.Add(1)
	go wechat.synccheck(wgp, heartbeatTube)
	wgp.Add(1)
	go wechat.messaging(wgp, heartbeatTube)

	//获取好友列表
	//if err := wechat.webwxgetcontact(); err != nil {
	//	fmt.Println(err)
	//}

	return nil
}

// 0 正常
// 2 新的消息
// 4 通过时发现，删除好友
// 6 删除时发现和对方通过好友验证
// 7 进入/离开聊天界面 （可能没有了）
func (w WechatUser) messaging(wgp *sync.WaitGroup, heartbeatTube chan string) {
	defer wgp.Done()
	for {
		switch v := <-heartbeatTube; v {
		case "0":
			fmt.Println("正常")
		case "2":
			fmt.Println("新消息")
			if err := w.webwxsync(); err != nil {
				fmt.Println(err)
			}
		case "4":
		case "6":
		case "7":
		case "fails":
			fmt.Println("消息停止")
			goto fails
		default:
		}
	}
fails:
}

func (w *WechatUser) webwxsync() error {
	webwxsync := modelwechat.WebwxsyncNewConfig(w.WebwxnewLoginPage, w.UserData.SyncKeys)
	body, _, err := tools.Post(w.HostPrefix.WebPush+configswechat.Webwxsync, webwxsync.Get, webwxsync.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("接收消息请求失败：%v", err))
	}
	var msg *modelwechat.WxSyncMsgCollect
	if err := json.Unmarshal(body, &msg); err != nil {
		return errors.New(fmt.Sprintf("接收消息格式转换失败：%v", err))
	}
	//更新 SyncKeys 防止得到的消息叠加
	w.UserData.SyncKeys = msg.SyncKeys
	////写入文件
	if err := w.userRecord(); err != nil {
		panic(err)
	}
	for _, v := range msg.MsgList {
		if v.FromUserName == w.UserData.User.UserName {
			fmt.Println("自己发的消息不进行回复")
			continue
		}
		msgType := configswechat.MsgTypeList[v.MsgType]
		fmt.Printf("消息类型：%v\n", msgType)
		switch v.MsgType {
		case 1:
			fmt.Println("接收到消息")
			//取出内容
			//判断是否是群消息
			go func() {
				if err := w.sendMsgText(modelwechat.MsgUser{
					FromUserName: v.ToUserName,
					ToUserName:   v.FromUserName,
				}, w.Ai.Send(w.stringGroup(v.Content), v.FromUserName)); err != nil {
					fmt.Println(err)
				}
			}()
			fmt.Println(v.Content)
		case 3: //图片
			if err := w.webwxgetmsgimg(v); err != nil {
				fmt.Println(err)
			}
		case 34: //语音
			if err := w.webwxgetvoice(v.MsgId); err != nil {
				fmt.Println(err)
			}
		case 37: //添加好友同意
			if err := w.webwxverifyuser(v.RecommendInfo.UserName, v.RecommendInfo.Ticket); err != nil {
				fmt.Println(err)
			}
		case 43: //视频
			if err := w.webwxgetvideo(v.MsgId); err != nil {
				fmt.Println(err)
			}
		case 49: //文件
			//需要先解析再进行操作
			if err := w.webwxgetmedia(v); err != nil {
				fmt.Println(err)
			}
		default:

		}
	}
	return nil
}

func (w *WechatUser) synccheck(wgp *sync.WaitGroup, heartbeatTube chan string) {

	defer wgp.Done()

	for {
		w.StartTime++ //这个开始时间需要自增
		body, _, err := tools.Get(w.HostPrefix.WebPush+configswechat.Synccheck, *modelwechat.SynccheckNewConfig(w.WebwxnewLoginPage, &w.UserData.SyncKeys, w.StartTime), w.userHeader(), w.userClient(true))
		if err != nil {
			fmt.Println(fmt.Sprintf("心跳请求失败:%v", err))
			goto fails
		}
		reg := regexp.MustCompile(`window.synccheck=\{retcode:"(.+)",selector:"(.+)"}`)
		submatch := reg.FindStringSubmatch(string(body))
		if len(submatch) != 3 {
			fmt.Println("心跳正则匹配失败")
			goto fails
		}

		switch submatch[1] {
		case "0":
			//消息状态码
			heartbeatTube <- submatch[2]
		case "1100":
			fmt.Println("失败/登出微信")
			goto fails
		case "1101":
			fmt.Println("微信在其他地方登录")
			goto fails
		case "1102":
			fmt.Println("微信退出")
			goto fails
		default:
			fmt.Printf("未识别登录Code:%v\n", submatch[1])
		}
		//进行延迟触发
		time.Sleep(time.Second * 5)
	}
fails:
	heartbeatTube <- "fails"
	if err := tools.FileDelete(configswechat.CacheSaveFile); err != nil {
		fmt.Println(err)
	}
}

func (w *WechatUser) webwxstatusnotify() error {
	webwxstatusnotify := modelwechat.WebwxstatusnotifyNewConfig(w.WebwxnewLoginPage, &w.UserData.User)
	_, _, err := tools.Post(w.Host+configswechat.Webwxstatusnotify, webwxstatusnotify.WebwxstatusnotifyGet, webwxstatusnotify.WebwxstatusnotifyPost, w.userHeader(&tools.Header{Key: "Accept", Value: "application/json;charset=UTF-8"}), w.userClient(false))
	if err != nil {
		return errors.New(fmt.Sprintf("通知微信登陆成功失败-：%v", err))
	}
	return nil
}

func (w *WechatUser) webwxinit() error {
	webxin := modelwechat.WebwxinitNewConfig(w.WebwxnewLoginPage)
	body, _, err := tools.Post(w.Host+configswechat.Webwxinit, webxin.Get, webxin.Post, w.userHeader(&tools.Header{Key: "Accept", Value: "application/json;charset=UTF-8"}), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("初始化信息失败：%v", err))
	}
	var data *modelwechat.UserData
	if err := json.Unmarshal(body, &data); err != nil {
		return errors.New(fmt.Sprintf("初始化信息失败-解析格式失败:%v", err))
	}
	w.UserData = data
	return nil
}

func (w *WechatUser) successfulSignal(statusTube chan string) (errs error) {

	for {
		select {
		case uri := <-statusTube:

			body, resp, err := tools.Get(uri+"&fun=new&version=v2&mod=desktop", nil, w.userHeader(), w.userClient(false))
			if err != nil {
				return errors.New(fmt.Sprintf("回调域名请求-%v", err))
			}

			host, err := tools.UrlToHost(uri)
			if err != nil {
				return errors.New(fmt.Sprintf("回调域名正则处理-%v", err))
			}

			var webwxnewLoginPage *modelwechat.WebwxnewLoginPage
			if err := xml.Unmarshal(body, &webwxnewLoginPage); err != nil {
				return errors.New(fmt.Sprintf("回调返回内容xml失败-%v", err))
			}
			if webwxnewLoginPage.Ret != 0 {
				return errors.New(fmt.Sprintf("验证登录失败-%v", webwxnewLoginPage.Message))
			}

			w.Cookie = resp.Cookies()
			w.Host = host
			w.HostPrefix = modelwechat.PrefixNewConfig(host)
			w.WebwxnewLoginPage = webwxnewLoginPage
			w.Ai = ai.Init("ollama")
			w.CookieToJson()
			return nil
		}
	}
}

func (w WechatUser) userClient(isCookie bool) *http.Client {

	client := &http.Client{
		Timeout: 18000 * time.Second,
	}
	if isCookie {
		u, err := url.Parse("https://wx.qq.com")
		if err != nil {
			panic(fmt.Sprintf("code获取域名：失败-%v", err))
		}
		jar := modelwechat.NewCookieJar()
		jar.SetCookies(u, w.Cookie)
		client.Jar = jar
	}
	return client
}

func (w WechatUser) userHeader(more ...*tools.Header) []*tools.Header {
	extspam := modelwechat.ExtspamNewConfig()
	return append(extspam, more...)
}

func (w WechatUser) userRecord() error {
	content, err := json.Marshal(w)
	if err != nil {
		return errors.New(fmt.Sprintf("格式解析失败：%v", err))
	}

	if err := tools.FileWrites(configswechat.CacheSaveFile, content); err != nil {
		return errors.New(fmt.Sprintf("文件写入失败：%v", err))
	}
	return nil
}

func (w *WechatUser) CookieToJson() {
	cookies := make(map[string]string)
	for _, cookie := range w.Cookie {
		cookies[cookie.Name] = cookie.Value
	}
	w.Cookies = cookies
}

// 群消息和普通消息处理
func (w WechatUser) stringGroup(content string) string {
	reg := regexp.MustCompile(`@.*?:<br/>(.*)`)
	submatch := reg.FindStringSubmatch(content)
	if len(submatch) != 2 {
		return content
	}
	return submatch[1]
}

//------获取好友

func (w WechatUser) webwxgetcontact() error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgetcontact, *modelwechat.WebwxgetcontactNewConfig(w.WebwxnewLoginPage), w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("获取好友列表失败：%v", err))
	}
	var friend *modelwechat.WxFriend
	if err := json.Unmarshal(body, &friend); err != nil {
		return errors.New(fmt.Sprintf("解析好友列表失败：%v", err))
	}
	for _, v := range friend.MemberList {
		if v.KeyWord == "" {
			if err := w.webwxgeticon(v.UserName); err != nil {
				fmt.Println(err)
			}
			fmt.Println(v.NickName, v.UserName)
		}
	}
	return nil
}

//------消息

// 发送文本信息
func (w *WechatUser) sendMsgText(user modelwechat.MsgUser, content string) error {
	webwxsendmsg := modelwechat.WebwxsendmsgNewConfig(w.WebwxnewLoginPage, user, content)
	_, _, err := tools.Post(w.Host+configswechat.Webwxsendmsg, webwxsendmsg.Get, webwxsendmsg.Post, w.userHeader(), w.userClient(false))
	if err != nil {
		return errors.New(fmt.Sprintf("发送文本消息失败：%v", err))
	}
	return nil
}

// 发送图片消息
func (w *WechatUser) sendMsgImage(user modelwechat.MsgUser, content string) error {

	filePath := "./th.jpg"

	file, err := tools.File(filePath)
	if err != nil {
		return err
	}

	webwxuploadmedia := modelwechat.WebwxuploadmediaNewConfig(w.WebwxnewLoginPage, user, w.Cookies, file.Info, file.MimeType, file.Md5Hash, "pic") //w.Host+configswechat.Webwxuploadmedia
	body, _, err := tools.Upload(w.Host+configswechat.Webwxuploadmedia, filePath, webwxuploadmedia.Get, webwxuploadmedia.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("上传文件失败：%v", err))
	}
	var wechatFile *modelwechat.WxUploadFile
	if err := json.Unmarshal(body, &wechatFile); err != nil {
		return errors.New(fmt.Sprintf("解析文件失败：%v", err))
	}
	webwxsendmsgimg := modelwechat.WebwxsendmsgimgNewConfig(w.WebwxnewLoginPage, user, wechatFile.MediaId)
	body, _, err = tools.Post(w.Host+configswechat.Webwxsendmsgimg, webwxsendmsgimg.Get, webwxsendmsgimg.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("发送图片消息失败：%v", err))
	}

	return nil
}

// 发送文件消息
func (w *WechatUser) sendMsgFile(user modelwechat.MsgUser, content string) error {
	filePath := "./session.log"

	file, err := tools.File(filePath)
	if err != nil {
		return err
	}
	webwxuploadmedia := modelwechat.WebwxuploadmediaNewConfig(w.WebwxnewLoginPage, user, w.Cookies, file.Info, file.MimeType, file.Md5Hash, "doc")
	body, _, err := tools.Upload(w.Host+configswechat.Webwxuploadmedia, filePath, webwxuploadmedia.Get, webwxuploadmedia.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("上传文件失败：%v", err))
	}
	var wechatFile *modelwechat.WxUploadFile
	if err := json.Unmarshal(body, &wechatFile); err != nil {
		return errors.New(fmt.Sprintf("解析文件失败：%v", err))
	}
	filename, ext := tools.FilePathToFilename(filePath)
	appmsg := modelwechat.WebwxsendappmsgAppmsgNewConfig(filename, wechatFile.MediaId, ext)

	xmlMsg, err := tools.StructToXml(appmsg)
	if err != nil {
		return err
	}
	webwxsendappmsg := modelwechat.WebwxsendappmsgNewConfig(w.WebwxnewLoginPage, user, strings.ReplaceAll(xmlMsg, "\"", "'"))

	//
	body, _, err = tools.Post(w.Host+configswechat.Webwxsendappmsg, webwxsendappmsg.Get, webwxsendappmsg.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return errors.New(fmt.Sprintf("发送文件消息失败：%v", err))
	}
	fmt.Println(string(body))
	return nil
}

//----附加操作

// 获取聊天中的图片
func (w WechatUser) webwxgetmsgimg(msg modelwechat.WxSyncMsg) error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgetmsgimg, *modelwechat.WebwxgetmsgimgNewConfig(w.WebwxnewLoginPage, msg.MsgId), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	if err := tools.FileWrites(fmt.Sprintf("./user/%s/msg/image/%s-%s-%v.jpg", w.UserData.User.UserName, msg.ToUserName, msg.FromUserName, time.Now().Unix()), body); err != nil {
		return err
	}
	return nil
}

// 获取头像
func (w WechatUser) webwxgeticon(username string) error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgeticon, *modelwechat.WebwxgeticonNewConfig(w.WebwxnewLoginPage, username), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	if err := tools.FileWrites(fmt.Sprintf("./user/%s/avatar/user/%s.jpg", w.UserData.User.UserName, username), body); err != nil {
		return err
	}
	return nil
}

// 获取群头像
func (w WechatUser) webwxgetheadimg(username string) error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgetheadimg, *modelwechat.WebwxgetheadimgNewConfig(w.WebwxnewLoginPage, username), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	if err := tools.FileWrites(fmt.Sprintf("./user/%s/avatar/crowd/%s.jpg", w.UserData.User.UserName, username), body); err != nil {
		return err
	}
	return nil
}

// 获取聊天中的视频
func (w WechatUser) webwxgetvideo(msgId string) error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgetvideo, *modelwechat.WebwxgetvideoNewConfig(w.WebwxnewLoginPage, msgId), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	if err := tools.FileWrites(fmt.Sprintf("./user/%s/msg/mp4/%s.mp4", w.UserData.User.UserName, msgId), body); err != nil {
		return err
	}
	return nil
}

// 获取聊天中的音频
func (w WechatUser) webwxgetvoice(msgId string) error {
	body, _, err := tools.Get(w.Host+configswechat.Webwxgetvoice, *modelwechat.WebwxgetvoiceNewConfig(w.WebwxnewLoginPage, msgId), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	if err := tools.FileWrites(fmt.Sprintf("./user/%s/msg/mp3/%s.mp3", w.UserData.User.UserName, msgId), body); err != nil {
		return err
	}
	return nil
}

// 获取聊天中的文件
func (w WechatUser) webwxgetmedia(wxMsg modelwechat.WxSyncMsg) error {
	body, _, err := tools.Get(w.HostPrefix.File+configswechat.Webwxgetmedia, *modelwechat.WebwxgetmediaNewConfig(w.WebwxnewLoginPage, w.UserData, w.Cookies, modelwechat.MsgUser{
		FromUserName: wxMsg.FromUserName,
		ToUserName:   wxMsg.ToUserName,
	}, wxMsg.FileName, wxMsg.MediaId), w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}

	if err := tools.FileWrites(fmt.Sprintf("./user/%s/msg/file/%s", w.UserData.User.UserName, wxMsg.FileName), body); err != nil {
		return err
	}
	return nil
}

// 好友验证通过
func (w WechatUser) webwxverifyuser(username string, ticket string) error {
	webwxverifyuser := modelwechat.WebwxverifyuserNewConfig(w.WebwxnewLoginPage, []modelwechat.WebwxverifyuserVerifyUser{
		modelwechat.WebwxverifyuserVerifyUser{
			Value:            username,
			VerifyUserTicket: ticket,
		},
	})
	body, _, err := tools.Post(w.Host+configswechat.Webwxverifyuser, webwxverifyuser.Get, webwxverifyuser.Post, w.userHeader(), w.userClient(true))
	if err != nil {
		return err
	}
	fmt.Println(string(body))
	return nil
}
